// LiteLoader-AIDS automatic generated
/// <reference path="c:\Users\Yoyo\Documents\mcbe/dts/llaids/src/index.d.ts"/> 

ll.registerPlugin(
    /* name */ "Sign shop",
    /* introduction */ "木牌商店",
    /* version */[0, 0, 7],
    /* otherInformation */ {
        author: 'Yoyo'
    }
);


let CONFIG = new JsonConfigFile(".\\plugins\\Yoyo\\SignShop\\config.json", '{ "LLMoney":1,"score": "","alias": "ShowName","limit":4}');
let antiShake = null;
let antObj = {
    player: null, item: null, block: null
}
let DB = new KVDatabase(".\\plugins\\Yoyo\\SignShop\\database");
//监听
let Monitor = [
    ["onDestroyBlock", onDestroyBlock], //破坏方块完成
    ["onUseItemOn", onUseItemOn], //玩家使用物品点击方块
    ["onPistonPush", onPistonPush], //活塞推动
    ["onBlockExploded", onBlockExploded], //方块被爆炸破坏
    ["onServerStarted", onServerStarted], //服务器启动完毕
].forEach(a => mc.listen(a[0], a[1]));
// log
let dates = system.getTimeObj();
logger.setFile(".\\plugins\\Yoyo\\SignShop\\log\\" + dates.Y + "-" + dates.M + "-" + dates.D + ".log");
logger.setConsole(false);
logger.setTitle("SignShop");


//注册命令
[{ cmd: "reloadsp", description: "-reload config", callback: OpenExc, level: 1 }].forEach(i =>
    mc.regPlayerCmd(i.cmd, i.description, i.callback, i.level)
);
//触发函数
function OpenExc(player, args) {
    CONFIG.reload();
    player.tell("§l§2Overload configuration successful!");
}

function onDestroyBlock(player, block) {
    if (block.type == "sign" || (block.type.indexOf("_sign") != -1 && block.hasBlockEntity())) {
        //是木牌

        if (isSign(signID(block.pos)) != null && !player.isOP()) {
            let blockE = block.getBlockEntity();
            let Enbt = blockE.getNbt();
            let text = Enbt.getTag("Text").get();
            let textArray = text.split("\n");
            let xType = textArray[0].replace(/^\[(.*)\]$/, "$1");
            blockE.setNbt(Enbt);
            player.tell(`§4${/^\w+$/.test(xType) ? "You have no right to tear it down" : "你无权拆毁它"}!`);
            return false;
        } else {
            destroy(signID(block.pos)); //摧毁
        }
    }
}

function onUseItemOn(player, item, block) {
    if (block.type == "sign" || (block.type.indexOf("_sign") != -1 && block.hasBlockEntity())) {
        //是木牌
        if (antiShake != null) clearInterval(antiShake);
        antObj.player = player;
        antObj.item = item;
        antObj.block = block;
        antiShake = setTimeout(NewItemOn, 80);
        return false;
    }
}

function NewItemOn() {
    logPath();
    let player, item, block;
    player = antObj.player;
    // item = antObj.item;
    item = player.getHand();
    block = antObj.block;
    let cScore = null;
    let cAlias = null;
    if (!CONFIG.get("LLMoney")) {
        cScore = CONFIG.get("score");
    }
    cAlias = CONFIG.get("alias");
    let signId = signID(block.pos);
    let signS = isSign(signId);
    if (signS == null) {
        //不存在 op创建 普通玩家拦截
        if (player.isOP()) {
            //是op
            //判断木牌格式
            let blockET = block.getBlockEntity();
            let blockNbt = blockET.getNbt();
            let FrontText = blockNbt.getTag("FrontText");
            let text = FrontText.getTag("Text")?.get() ?? '';
            let textArray = text.split("\n");
            if (!isTypeShop(textArray[0])) return false; //类型不对
            if (!/^\d{1,3}$/.test(textArray[2])) return false; //不是数字或者太长
            if (!/^\d{1,10}$/.test(textArray[3])) return false; //不是数字或者太长
            if (!cScore && !CONFIG.get("LLMoney")) {
                player.tell("§l§4Configure to set currency entries in the file");
                return false;
            }
            if (!CONFIG.get("LLMoney") && !mc.getScoreObjective(cScore)) {
                player.tell("§l§4The configured score item is not created");
                return false;
            }
            if (item.isNull()) return false; //是空手
            let itemNbt = item.getNbt();
            itemNbt.setByte("Count", 1);
            let itemSNbt = itemNbt.toSNBT(); //转snbt
            let Base64Snbt = data.toBase64(itemSNbt);
            if (!DB.set(signId, Base64Snbt)) {
                //存起来
                player.tell("§4fail to save");
                return false;
            }
            //修改木牌文字
            FrontText.setString(
                "Text",
                `[${textArray[0]}]\n${textArray[1]}\n${/^\w+$/.test(textArray[0]) ? "Count" : "数量"}: ${textArray[2]}\n${cAlias}: ${textArray[3]
                }`
            );
            blockET.setNbt(blockNbt);
            player.tell("§l§2Success");
        } else {
            //不是op
            return false;
        }
    } else {
        //存在直接交易
        let blockET = block.getBlockEntity();
        let Nbt = blockET.getNbt();
        let FrontText = Nbt.getTag("FrontText");
        let text = FrontText.getTag("Text")?.get() ?? '';
        let textArray = text.split("\n");
        if (!/^\[.*\]$/.test(textArray[0])) {
            FrontText.setString(
                "Text",
                `[${textArray[0]}]\n${textArray[1]}\n${/^\w+$/.test(textArray[0]) ? "Count" : "数量"}: ${textArray[2]}\n${cAlias}: ${textArray[3]
                }`
            );
            blockET.setNbt(Nbt);
        }

        let xType = textArray[0].replace(/^\[(.*)\]$/, "$1");
        if (xType == null) {
            player.tell("§l§4Sign Shop Error 1");
            return false;
        }
        //限制距离
        if (!limitDistance(player, block)) {
            player.tell(`§l§8${/^\w+$/.test(xType) ? "You're too far away. Can you come a little closer?" : "你距离太远了,可以近一点吗?"}`);
            return false;
        }
        let xCount = parseInt(textArray[2].replace(/^[^\d]*(\d+)$/, "$1"));
        if (xCount == null) {
            player.tell("§l§4Sign Shop Error 3");
            return false;
        }
        let xMoney = parseInt(textArray[3].replace(/^[^\d]*(\d+)$/, "$1"));
        if (xMoney == null) {
            player.tell("§l§4Sign Shop Error 4");
            return false;
        }
        if (!cScore && !CONFIG.get("LLMoney")) {
            player.tell("§l§4Configure to set currency entries in the file");
            return false;
        }
        if (!CONFIG.get("LLMoney") && !mc.getScoreObjective(cScore)) {
            player.tell("§l§4The configured score item is not created");
            return false;
        }
        let Pmoney = null;
        if (CONFIG.get("LLMoney")) {
            Pmoney = money.get(player.xuid);
        } else {
            Pmoney = player.getScore(cScore);
        }

        if (["sell", "出售"].includes(xType)) {
            //出售
            if (Pmoney < xMoney) {
                player.tell(`§l§4${/^\w+$/.test(xType) ? cAlias + " Insufficient" : cAlias + " 不够"}`);
                return false;
            }
            if (CONFIG.get("LLMoney")) {
                money.reduce(player.xuid, xMoney);
            } else {
                player.reduceScore(cScore, xMoney); //扣
            }

            let qSnbt = DB.get(signId);

            let Nbt = NBT.parseSNBT(data.fromBase64(qSnbt));
            Nbt.setByte("Count", xCount);
            let NewItem = mc.newItem(Nbt);
            let GetPlItem = player.giveItem(NewItem);
            if (!GetPlItem) {
                //背包满掉落
                mc.spawnItem(NewItem, player.pos.x, player.pos.y, player.pos.z, player.pos.dimid);
                player.tell(`§l§2${/^\w+$/.test(xType) ? "Rucksack full, items dropped" : "背包已满,物品已掉落"}`);
                logger.info(`§l§2${/^\w+$/.test(xType) ? "[" + player.name + "]Buy " + xCount + " [" + NewItem.type + "] but the backpack was full and dropped on the floor" : "[" + player.name + "]购买 " + xCount + " 件 [" + NewItem.type + "] 但是背包满了,掉地上了"}`);
            } else {
                //刷新背包
                player.refreshItems();
                player.tell(
                    `§l§2${/^\w+$/.test(xType)
                        ? "Successful purchase of " + xCount + " [" + textArray[1] + "] has been put into the backpack"
                        : "成功购买 " + xCount + " 件 [" + textArray[1] + "] 已放入背包"
                    }`
                );
                logger.info(
                    `§l§2${/^\w+$/.test(xType)
                        ? "[" + player.name + "] Successful purchase of " + xCount + " [" + NewItem.type + "] has been put into the backpack"
                        : "[" + player.name + "] 成功购买 " + xCount + " 件 [" + NewItem.type + "] 已放入背包"
                    }`
                );
            }
        } else if (["recycle", "回收"].includes(xType)) {
            //回收
            let plItemObj = player.getInventory();
            let AllVesselList = plItemObj.getAllItems();
            let qSnbt = DB.get(signId);
            let Nbt = NBT.parseSNBT(data.fromBase64(qSnbt));
            let NewItem = mc.newItem(Nbt);
            // log(NewItem.type, NewItem.aux);//物品类型和特殊值
            let isSoonArr = []; //符合要求的物品
            AllVesselList.forEach((v, k) => {
                let IndexItemObj = plItemObj.getItem(k);
                if (IndexItemObj.type == NewItem.type && IndexItemObj.aux == NewItem.aux) {
                    isSoonArr.push(IndexItemObj);
                }
            });
            if (isSoonArr.length == 0) {
                //直接没有物品
                player.tell(`§l§4${/^\w+$/.test(xType) ? " You don't have the item" : " 你没有该物品"}`);
                return false;
            }
            let ItemCount = isSoonArr.map(a => a.count).reduce((a, b) => a + b);
            if (ItemCount < xCount) {
                player.tell(
                    `§l§4${/^\w+$/.test(xType)
                        ? " Insufficient quantity of goods " + ItemCount + "/" + xCount
                        : " 物品数量不足 " + ItemCount + "/" + xCount
                    }`
                );
                return false;
            }
            //情空该物品
            AllVesselList.forEach((v, k) => {
                let IndexItemObj = plItemObj.getItem(k);
                if (IndexItemObj.type == NewItem.type && IndexItemObj.aux == NewItem.aux) {
                    plItemObj.removeItem(k, 64);
                }
            });
            let itemNewCount = ItemCount - xCount;
            for (let isa = 0; itemNewCount > 64; isa++) {
                Nbt.setByte("Count", 64);
                plItemObj.addItemToFirstEmptySlot(mc.newItem(Nbt));
                itemNewCount -= 64;
            }
            Nbt.setByte("Count", itemNewCount);
            plItemObj.addItemToFirstEmptySlot(mc.newItem(Nbt));
            if (CONFIG.get("LLMoney")) {
                money.add(player.xuid, xMoney);
            } else {
                player.addScore(cScore, xMoney);
            }

            player.refreshItems();
            player.tell(
                `§l§2${/^\w+$/.test(xType)
                    ? "You get " + xMoney + " for successfully selling " + xCount + " [" + textArray[1] + "] " + cAlias
                    : "成功出售" + xCount + "个 [" + textArray[1] + "] 获得" + xMoney + " " + cAlias
                }`
            );
            logger.info(
                `§l§2${/^\w+$/.test(xType)
                    ? "[" + player.name + "]You get " + xMoney + " for successfully selling " + xCount + " [" + NewItem.type + "] " + cAlias
                    : "[" + player.name + "]成功出售" + xCount + "个 [" + NewItem.type + "] 获得" + xMoney + " " + cAlias
                }`
            );
        } else {
            player.tell("§l§4Sign Shop Error Type"); //错误的商店
        }
    }
    return false;
}

function onPistonPush(pistonPos, block) {
    if (isSign(signID(block.pos))) {
        return false;
    }
}

function onBlockExploded(block, source) {
    destroy(signID(block.pos)); //摧毁
}

function signID(pos) {
    return data.toMD5(`sign_${pos.dimid}_${pos.x}_${pos.y}_${pos.z}`);
}

function isSign(sid) {
    return DB.get(sid);
}

function isTypeShop(str) {
    let type = ["sell", "出售", "回收", "recycle"];
    return type.includes(str);
}

function destroy(sid) {
    DB.delete(sid);
}

function onServerStarted() {
    colorLog("green", "[Yoyo] The sign shop is up and running (v0.0.6)");
}

function logPath() {
    let dates = system.getTimeObj();
    let path = ".\\plugins\\Yoyo\\SignShop\\log\\" + dates.Y + "-" + dates.M + "-" + dates.D + ".log";
    if (!file.exists(path)) {
        logger.setFile(path);
    }
}


function limitDistance(pos1, pos2) {
    let status = true;
    let limits = CONFIG.get("limit");
    if (typeof limits == "undefined") {
        CONFIG.set("limit", 2);
        CONFIG.reload();
        limits = 2;
    }
    let dx = pos1.pos.x - pos2.pos.x;
    let dy = pos1.pos.y - pos2.pos.y
    let dz = pos1.pos.z - pos2.pos.z;
    let ams = (dx * dx) + (dy * dy) + (dz * dz);
    if (Math.sqrt(ams) > limits) {
        status = false;
    }
    return status;
}